`include "param.v"  


module Controler (
    input wire [6:0] opcode,
    input wire [2:0] funct3,
    input wire [6:0] funct7,

    output reg [2:0] npc_op,//连接到npc模块的控制信号
    output reg alub_sel,//选择ALU的B是rd2还是imm
    output reg alua_sel,
    output reg [4:0] alu_op,
    output reg [2:0] sext_op,
    output reg rf_we,
    output reg [1:0] rf_wsel,
    output reg ram_we,
    output reg [2:0] S_op,
    output reg [2:0] Ld_op,
    output reg ID_rs1_use,
    output reg ID_rs2_use

);

    //定义npc_op
    //定义npc_op的信号值
parameter  NPC_PC4 =3'b000;
parameter  NPC_BEQ =3'b001;
parameter  NPC_BNE =3'b010;
parameter  NPC_BLT =3'b011;
parameter  NPC_BGE =3'b100;
parameter  NPC_JAL =3'b101;
parameter  NPC_JALR =3'b110;


//npc_op
always @(*) begin
    case (opcode)
    `R_op: npc_op = NPC_PC4;
    `I_op: npc_op =NPC_PC4;
    `lui_op: npc_op = NPC_PC4;
    `L_op: npc_op = NPC_PC4;
    `jal_op: npc_op = NPC_JAL;
    `jalr_op: npc_op = NPC_JALR;
    `B_op:begin
        case (funct3)
            'b000: npc_op =NPC_BEQ;
            'b001: npc_op = NPC_BNE;
            'b100: npc_op = NPC_BLT;
            'b101: npc_op = NPC_BGE;
            'b110: npc_op = NPC_BLT;//bltu和blu共用npc_OP信号
            'b111: npc_op = NPC_BGE;//bgeu和bge共用npc_OP信号
            default: npc_op = NPC_PC4;
        endcase
    end
    `auipc_op: npc_op = NPC_PC4;
    `S_op:npc_op = NPC_PC4;
    default:npc_op = NPC_PC4;
endcase
end

//alua_sel
always @(*) begin
    if(opcode == `auipc_op)begin
        alua_sel = 1;
    end
    else begin
        alua_sel = 0;
    end
end

//alub_op  alub_sel
always @(*) begin
    if (opcode == `R_op||opcode == `B_op)begin
        alub_sel = 0;//0表示选择rd2
    end
    else if(opcode == `jalr_op||opcode==`L_op||opcode==`I_op||opcode==`S_op||opcode == `auipc_op)begin
        alub_sel = 1;//1表示选择imm
    end
    else begin
        alub_sel = 0;
    end
end


//alu_op
always @(*) begin
    case (opcode)
        `R_op:begin
             if(funct3 == 3'b000 && funct7 == 7'b0000000)begin
                alu_op = `ALU_ADD;
             end
             else if(funct3 == 3'b000 && funct7 == 7'b0100000)begin
                alu_op = `ALU_SUB;
             end
             else if(funct3 == 3'b111 && funct7 == 7'b0000000)begin
                alu_op = `ALU_AND;
             end
             else if(funct3 == 3'b110 && funct7 == 7'b0000000)begin
                alu_op = `ALU_OR;
             end
             else if(funct3 == 3'b100 && funct7 == 7'b0000000)begin
                alu_op = `ALU_XOR;
             end
             else if(funct3 == 3'b001 && funct7 == 7'b0000000)begin
                alu_op = `ALU_SLL;
             end
             else if(funct3 == 3'b101 && funct7 == 7'b0000000)begin
                alu_op = `ALU_SRL;
             end
             else if(funct3 == 3'b101 && funct7 == 7'b0100000)begin
                alu_op = `ALU_SRA;
             end
             else if(funct3 ==3'b010 && funct7 == 7'b0000000)begin
                alu_op = `ALU_SLT;
             end
             else if(funct3 ==3'b011 && funct7 == 7'b0000000)begin
                alu_op = `ALU_SLTU;
             end
             else alu_op = `ALU_ADD;
            
        end 
        `I_op:begin
            if(funct3 == 3'b000)begin
                alu_op = `ALU_ADD;
             end
             else if(funct3 == 3'b111)begin
                alu_op = `ALU_AND;
             end
             else if(funct3 == 3'b110)begin
                alu_op = `ALU_OR;
             end
             else if(funct3 == 3'b100)begin
                alu_op = `ALU_XOR;
             end
             else if(funct3 == 3'b001 && funct7 == 7'b0000000)begin
                alu_op = `ALU_SLL;
             end
             else if(funct3 == 3'b101&&funct7 == 7'b0000000)begin
                alu_op = `ALU_SRL;
             end
             else if(funct3 == 3'b101&&funct7 == 7'b0100000)begin
                alu_op = `ALU_SRA;
             end
              else if(funct3 == 3'b010)begin
                alu_op = `ALU_SLT;//其实是SLTI
             end
              else if(funct3 == 3'b011)begin
                alu_op = `ALU_SLTU;//其实是sltiu
             end
             else alu_op = `ALU_ADD;
        end
        `L_op:begin
            alu_op = `ALU_ADD;
        end
        `S_op:begin
            alu_op = `ALU_ADD;
        end
        `jalr_op:begin
            alu_op = `ALU_JALR;
        end
        `auipc_op:begin
            alu_op = `ALU_ADD;
        end
        `B_op:begin
            if(funct3 == 3'b000)begin
                alu_op = `ALU_BEQ; 
            end
            else if(funct3 == 3'b001)begin
                alu_op = `ALU_BNE; 
            end
            else if(funct3 == 3'b100)begin
                alu_op = `ALU_BLT; 
            end
            else if(funct3 == 3'b101)begin
                alu_op = `ALU_BGE; 
            end
            else if(funct3 == 3'b110)begin
                alu_op = `ALU_BLTU; 
            end
            else if(funct3 == 3'b111)begin
                alu_op = `ALU_BGEU; 
            end
            else alu_op = `ALU_ADD;
        end
        
        default: alu_op = alu_op;
    endcase
end

//sext_op 第一版本

//   always @(*) begin
//         case(opcode)
//             `I_op: begin // I
//                 if(funct3 == 3'b000 || funct3 == 3'b111 || funct3 == 3'b110 || funct3 == 3'b100)
//                     sext_op = 3'b001;
//                 else if(funct3 == 3'b001 || funct3 == 3'b101)
//                     sext_op = 3'b000;
//                 else sext_op = 3'b000;
//             end
//             `lw_op: sext_op = `sext_lw; // lw
//             `jalr_op: sext_op = `sext_jalr; // lui
//             `S_op: sext_op = `sext_sw; // sw
//             `B_op: sext_op =   `sext_B; // jalr
//             `lui_op: sext_op = `sext_lui; // B
//             `jal_op: sext_op = `sext_jal; // jal
//             default:    sext_op = `sext_R;
//         endcase
//     end

//sext_op第二版本
  always @(*) begin
        case(opcode)
            7'b0010011: begin // I
                if(funct3 == 3'b000 || funct3 == 3'b111 || funct3 == 3'b110 || funct3 == 3'b100)
                    sext_op = 3'b000;
                else if(funct3 == 3'b001 || funct3 == 3'b101)
                    sext_op = 3'b001;
                else sext_op = 3'b000;
            end
            7'b0000011: sext_op = 3'b000; // lw
            7'b0110111: sext_op = 3'b011; // lui
            7'b0100011: sext_op = 3'b010; // sw
            7'b1100111: sext_op = 3'b000; // jalr
            7'b1100011: sext_op = 3'b100; // B
            7'b1101111: sext_op = 3'b101; // jal
            `auipc_op: sext_op = 3'b110; //auipc
            default:    sext_op = 3'b000;
        endcase
    end

    //rf_wsel
    always @(*) begin
        case (opcode)
           `R_op :rf_wsel = 2'b00;
           `I_op :rf_wsel = 2'b00;
           `lui_op :rf_wsel = 2'b01;
           `L_op :rf_wsel = 2'b10;
           `jalr_op :rf_wsel = 2'b11;
           `jal_op :rf_wsel = 2'b11;
           `auipc_op:rf_wsel = 2'b00;//auipc RF存入ALU_C的数据
            default: rf_wsel = rf_wsel;
        endcase
    end

    //rf_we
    always @(*) begin
        if(opcode == `B_op||opcode == `S_op)begin
          rf_we = 1'b0;
        end
        else begin
          rf_we = 1'b1;
        end
    end

    //ram_we
    always @(*) begin
        if(opcode == `S_op)begin
          ram_we = 1'b1;
        end
        else begin
          ram_we = 1'b0;
        end
    end

    //Ld_op
    always @(*) begin
        case (funct3)
            3'b000:    Ld_op = `L_lb;
            3'b100:    Ld_op = 'b100;
            3'b001:    Ld_op = `L_lh;
            3'b101:    Ld_op = `L_lhu;
            3'b010:    Ld_op = `L_lw; 
            default: Ld_op = `L_invalid;
        endcase
    end

    //S_op
    always @(*) begin
        case (funct3)
           3'b000 : S_op = `S_sb;
           3'b001 : S_op = `S_sh;
           3'b010 : S_op = `S_sw; 
            default: S_op = `S_invalid;
        endcase
    end


    //本条指令是否要用到rs1和rs2
    always @(*) begin
        ID_rs1_use = (opcode != `lui_op && opcode != `jal_op)? 1:0;
        ID_rs2_use = (opcode == `R_op||opcode == `B_op||opcode == `S_op)? 1:0;
    end

    
endmodule